package common

import (
	"context"
	"encoding/json"
	"github.com/gorhill/cronexpr"
	"strings"
	"time"
)

type Job struct {
	Name     string `json:"name"`
	Command  string `json:"command"`
	CronExpr string `json:"cronExpr"`
}

type JobSchedulePlan struct {
	Job      *Job
	Expr     *cronexpr.Expression
	NextTime time.Time
}

type JobExecuteInfo struct {
	Job       *Job
	PlanTime  time.Time       //理论上的调度时间
	RealTime  time.Time       //实际调度时间
	CancelCtx context.Context // 取消调度
	CancelFun context.CancelFunc
}

type JobExecuteResult struct {
	ExecuteInfo *JobExecuteInfo
	OutPut      []byte
	Err         error
	StartTime   time.Time
	EndTime     time.Time
}

type Response struct {
	ErrorNo int         `json:"errorNo"`
	Msg     string      `json:"msg"`
	Data    interface{} `json:"data"`
}

type JobEvent struct {
	EventType int //update /delete
	Job       *Job
}

type JobLog struct {
	JobName      string `bson:"jobName"`
	Command      string `bson:"command"`
	Err          string `bson:"err"`
	Output       string `bson:"output"`
	PlanTime     int64  `bson:"planTime"`
	ScheduleTime int64  `bson:"scheduleTime"`
	StartTime    int64  `bson:"startTime"`
	EndTime      int64  `bson:"endTime"`
}

type LogBatch struct {
	Logs []interface{}
}

func BuildResponse(errNo int, msg string, data interface{}) (resp []byte, err error) {
	var (
		response Response
	)
	response.ErrorNo = errNo
	response.Msg = msg
	response.Data = data

	resp, err = json.Marshal(response)
	return

}

func Unpack(value []byte) (ret *Job, err error) {
	var (
		job *Job
	)
	job = &Job{}

	if err = json.Unmarshal(value, job); err != nil {
		return
	}
	ret = job
	return
}

func ExtractJobName(name string, prefix string) (jobName string) {
	return strings.TrimPrefix(name, prefix)
}

func BuildJobEvent(eventJob int, job *Job) (jobEvent *JobEvent) {
	return &JobEvent{
		EventType: eventJob,
		Job:       job,
	}
}

func BuildCronPlan(job *Job) (plan *JobSchedulePlan, err error) {
	var (
		cronExpr *cronexpr.Expression
	)
	if cronExpr, err = cronexpr.Parse(job.CronExpr); err != nil {
		return
	}
	plan = &JobSchedulePlan{
		Job:      job,
		Expr:     cronExpr,
		NextTime: cronExpr.Next(time.Now()),
	}
	return
}

func BuildJobExecuteInfo(plan *JobSchedulePlan) (executeInfo *JobExecuteInfo) {
	executeInfo = &JobExecuteInfo{
		Job:      plan.Job,
		PlanTime: plan.NextTime,
		RealTime: time.Now(),
	}
	executeInfo.CancelCtx, executeInfo.CancelFun = context.WithCancel(context.TODO())
	return
}
